package com.nononsenseapps.feeder.ui

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.net.Uri
import android.os.Bundle
import android.view.*
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.*
import androidx.appcompat.app.AppCompatDelegate
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.gitee.wsl.common.ui.ext.lazyViewById
import com.google.android.material.slider.Slider
import com.kongzue.stacklabelview.StackLabel
import com.nononsenseapps.feeder.db.ARG
import com.nononsenseapps.feeder.db.URI_FEEDS
import com.nononsenseapps.feeder.db.room.ID_UNSET
import com.nononsenseapps.feeder.db.room.upsert
import com.nononsenseapps.feeder.ui.base.CoroutineScopedActivity
import com.nononsenseapps.feeder.ui.base.startMutableServer
import com.nononsenseapps.feeder.ui.common.FloatLabelLayout
import com.nononsenseapps.feeder.util.*
import com.nononsenseapps.feeder.worker.requestFeedSync
import com.nononsenseapps.jsonfeed.Feed
import kotlinx.coroutines.*
import java.net.URL

class EditFeedActivity : CoroutineScopedActivity() {
    private var feedId: Long = ID_UNSET
    // Views and shit
    //private lateinit var textTitle: EditText
    private val textTitle:EditText by lazyViewById(R.id.feed_title)

    private lateinit var textUrl: EditText
    private lateinit var textTag: AutoCompleteTextView
    private lateinit var textSearch: EditText
    private lateinit var detailsFrame: View
    private lateinit var listResults: RecyclerView
    private lateinit var resultAdapter: ResultsAdapter
    private lateinit var searchFrame: View

    private lateinit var emptyText: TextView
    private lateinit var loadingProgress: View
    private lateinit var urlLabel: FloatLabelLayout
    private lateinit var titleLabel:  FloatLabelLayout
    private lateinit var tagLabel:  FloatLabelLayout
    private lateinit var stackLabelView:StackLabel

    private lateinit var feedSyncPeriod:EditText
    private lateinit var feedSyncPeriodSlider: Slider

    private lateinit var switchSync:Switch
    private lateinit var ruleSync:Switch
    private lateinit var backupSwitch:Switch
    private lateinit var overwriteSwitch:Switch

    private lateinit var fullPageLoad:Switch
    private lateinit var preDownload:Switch
    private lateinit var imagePreDownload:Switch

    private lateinit var reFormatBody:Switch

    private lateinit var mutableServer:Switch

    private lateinit var mutableServerButton:Button

    private var feedUrl: String? = null
    private var feedTitle: String = ""

    private var template:Boolean=false

    var feed: com.nononsenseapps.feeder.db.entity.Feed? = null

    internal var searchJob: Job? = null
        set(value) {
            field?.cancel()
            field = value
        }

    @SuppressLint("ResourceAsColor")
    override fun onCreate(savedInstanceState: Bundle?) {
        if (shouldBeFloatingWindow()) {
            setupFloatingWindow()
        }
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_edit_feed)

        // Not persisted so set nightmode every time we start
        AppCompatDelegate.setDefaultNightMode(settingsViewModel.themePreference)

        // Setup views
        //textTitle = findViewById(R.id.feed_title)
        titleLabel = textTitle.parent as  FloatLabelLayout
        textUrl = findViewById(R.id.feed_url)
        urlLabel = textUrl.parent as  FloatLabelLayout
        textTag = findViewById(R.id.feed_tag)
        tagLabel = textTag.parent as  FloatLabelLayout
        detailsFrame = findViewById(R.id.feed_details_frame)
        searchFrame = findViewById(R.id.feed_search_frame)
        textSearch = findViewById(R.id.search_view)
        listResults = findViewById(R.id.results_listview)
        emptyText = findViewById(android.R.id.empty)
        loadingProgress = findViewById(R.id.loading_progress)

        stackLabelView=findViewById(R.id.stackLabelView)

        feedSyncPeriod=findViewById(R.id.feed_sync_period)
        feedSyncPeriodSlider=findViewById(R.id.feed_sync_slider)

        feedSyncPeriodSlider.apply {
            this.valueFrom=0f
            this.valueTo=12f
            this.stepSize= 1F
            this.trackTintList= ColorStateList.valueOf(R.color.icon_tint_color)
            this.setLabelFormatter {
                when(it){
                    0F -> "无间隔"
                    1F -> "10分钟"
                    2F -> "30分钟"
                    3F -> "1小时"
                    4F -> "6小时"
                    5F -> "12小时"
                    6F -> "1天"
                    7F -> "3天"
                    8F -> "一星期"
                    9F -> "半个月"
                    10F -> "一个月"
                    11F -> "一季度"
                    12F -> "半年"
                    else -> "no set"
                }
            }
        }
        feedSyncPeriodSlider.addOnChangeListener { _, value, fromUser ->
               if(fromUser){
                   var newSyncTimeValue=0
                   when(value){
                       0F -> newSyncTimeValue=0
                       1F -> newSyncTimeValue=10
                       2F -> newSyncTimeValue=30
                       3F -> newSyncTimeValue=60
                       4F -> newSyncTimeValue=60*6
                       5F -> newSyncTimeValue=60*12
                       6F -> newSyncTimeValue=60*24
                       7F -> newSyncTimeValue=60*24*3
                       8F -> newSyncTimeValue=60*24*7
                       9F -> newSyncTimeValue=60*24*15
                       10F -> newSyncTimeValue=60*24*30
                       11F -> newSyncTimeValue=60*24*30*4
                       12F -> newSyncTimeValue=60*24*30*6
                   }
                   feedSyncPeriod.setText(newSyncTimeValue.toString())
               }
        }

        switchSync=findViewById(R.id.feed_sync_able)
        ruleSync=findViewById(R.id.feed_rule_able)
        backupSwitch=findViewById(R.id.feed_backup)
        overwriteSwitch=findViewById(R.id.feed_overwrite)

        fullPageLoad=findViewById(R.id.feed_full_page_load)
        preDownload=findViewById(R.id.feed_pre_download)
        imagePreDownload=findViewById(R.id.feed_image_pre_download)

        reFormatBody=findViewById(R.id.feed_reformat_body)

        mutableServer=findViewById(R.id.feed_mutable_server)
        mutableServer.setOnCheckedChangeListener { buttonView, isChecked ->
            mutableServerButton.isEnabled=isChecked
        }

        mutableServerButton=findViewById(R.id.feed_mutable_server_view)
        mutableServerButton.setOnClickListener {
            startMutableServer(this,sloppyLinkToStrictURLNoThrows(textUrl.text.toString().trim()).toString())
        }

        resultAdapter = ResultsAdapter()

        //listResults.emptyView = emptyText
        listResults.setHasFixedSize(true)
        listResults.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
        listResults.adapter = resultAdapter

        textSearch.setOnEditorActionListener(TextView.OnEditorActionListener { _, actionId, event ->
            if (actionId == EditorInfo.IME_ACTION_GO ||
                    actionId == EditorInfo.IME_NULL && event.action == KeyEvent.ACTION_DOWN && event.keyCode == KeyEvent.KEYCODE_ENTER) {
                // Hide keyboard
                val f = currentFocus
                if (f != null) {
                    val imm = getSystemService(
                            Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(f.windowToken,
                            0)
                }

                searchFeed()

                return@OnEditorActionListener true
            }
            false
        })

        val addButton = findViewById<Button>(R.id.add_button)
        addButton.setOnClickListener { _ ->
            // TODO error checking and stuff like that
            val title = textTitle.text.toString().trim()
            val customTitle = if (title == feedTitle) {
                ""
            } else {
                title
            }
            val syncAble=switchSync.isChecked
            val syncPeriod:Int=feedSyncPeriod.text.toString().toIntOrNull()?:0
            val ruleAble=ruleSync.isChecked
            val backup=backupSwitch.isChecked
            val overwriteAble=overwriteSwitch.isChecked
            val fullPageLoadAble=fullPageLoad.isChecked
            val preDownloadAble=preDownload.isChecked
            val reFormatBodyAble=reFormatBody.isChecked
            val imagePreDownLoadAble=imagePreDownload.isChecked
            val mutableServerAble=mutableServer.isChecked

            if(feed==null||template)
               feed = com.nononsenseapps.feeder.db.entity.Feed(
                   id = ID_UNSET,
                   title = title,
                   customTitle = customTitle,
                   tag = textTag.text.toString().trim(),
                   url = sloppyLinkToStrictURLNoThrows(textUrl.text.toString().trim()),
                   syncAble = syncAble,
                   sync_period = syncPeriod,
                   ruleAble = ruleAble,
                   backup = backup,
                   overWrite = overwriteAble,
                   fullTextSync = fullPageLoadAble,
                   preDownload = preDownloadAble,
                   bodyReFormat = reFormatBodyAble,
                   imagePreDownload = imagePreDownLoadAble,
                   mutableServerFeed = mutableServerAble
               )
            else {
                feed?.apply {
                    this.title = title
                    this.customTitle = customTitle
                    this.tag = textTag.text.toString().trim()
                    this.url = sloppyLinkToStrictURLNoThrows(textUrl.text.toString().trim())
                    this.syncAble = syncAble
                    this.sync_period = syncPeriod
                    this.ruleAble=ruleAble
                    this.backup = backup
                    this.overWrite=overwriteAble
                    this.fullTextSync=fullPageLoadAble
                    this.preDownload=preDownloadAble
                    this.bodyReFormat=reFormatBodyAble
                    this.imagePreDownload=imagePreDownLoadAble
                    this.mutableServerFeed=mutableServerAble
                }
            }

            lifecycleScope.launch(Dispatchers.Default) {

                val feedId: Long = feedDao.upsert(feed!!)

                if(syncAble) {
                    requestFeedSync(context = this@EditFeedActivity, feedId = feedId, ignoreConnectivitySettings = false, forceNetwork = true)
                }
                val intent = Intent(Intent.ACTION_VIEW, Uri.withAppendedPath(URI_FEEDS, "$feedId"))
                intent.putExtra(ARG.TITLE, title)
                        .putExtra(ARG.LINK, feed!!.url.toString())
                        .putExtra(ARG.TAG, feed!!.tag)
                        .putExtra(ARG.FEED_SYNC,feed!!.syncAble)
                        .putExtra(ARG.FEED_SYNC_PERIOD,feed!!.sync_period)
                withContext(Dispatchers.Main) {
                    setResult(RESULT_OK, intent)
                    finish()
                }
            }
        }

        // Create an adapter
        lifecycleScope.launch(Dispatchers.IO) {
            val data = feedDao.loadTags()

            val tagsAdapter = ArrayAdapter<String>(this@EditFeedActivity,
                    android.R.layout.simple_list_item_1,
                    android.R.id.text1,
                    data)

            withContext(Dispatchers.Main) {
                // Set the adapter
                textTag.setAdapter(tagsAdapter)
                stackLabelView.labels = data
            }
        }

        stackLabelView.setOnLabelClickListener { _, _, s -> textTag.setText(s) }

        // Consider start intent
        val i = intent
        if (i != null) {
            // Existing id
            feedId = i.getLongExtra(ARG.FEED_ID, ID_UNSET)
            // Edit like existing, but it's really new
           template = i.getBooleanExtra(ARG.TEMPLATE, false)

            // Existing item
            if (feedId > ID_UNSET || template) {
                searchFrame.visibility = View.GONE
                detailsFrame.visibility = View.VISIBLE
                if (feedId > ID_UNSET) {
                    // Don't allow editing url, but allow copying the text
                    //textUrl.setInputType(InputType.TYPE_NULL);
                    //textUrl.setTextIsSelectable(true);
                    // Focus on tag
                    textTag.requestFocus()
                    addButton.text = getString(R.string.save)
                } else {
                    textUrl.requestFocus()
                }
            } else {
                searchFrame.visibility = View.VISIBLE
                detailsFrame.visibility = View.GONE
                // Focus on search
                searchFrame.requestFocus()
            }

            // Link
            feedUrl = (i.dataString ?: i.getStringExtra(Intent.EXTRA_TEXT) ?: "").trim()
            textSearch.setText(feedUrl)
            // URL
            textUrl.setText(feedUrl)

            // Title
            i.getStringExtra(ARG.TITLE)?.let {
                feedTitle = it
            }
            val customTitle=i.getStringExtra(ARG.CUSTOM_TITLE)?:""
            if (i.hasExtra(ARG.CUSTOM_TITLE) && customTitle.isNotBlank()) {
                textTitle.setText(customTitle)
            } else {
                textTitle.setText(feedTitle)
            }

            // Tag
            i.getStringExtra(ARG.TAG)?.let {
                // Use append instead of setText to make sure cursor is at end
                textTag.append(it)
            }

            // sync_able
            i.getBooleanExtra(ARG.FEED_SYNC,true).let {
                switchSync.isChecked=it
            }

            i.getIntExtra(ARG.FEED_SYNC_PERIOD,0).let{
                feedSyncPeriod.setText(it.toString())
            }

            if(feedId == ID_UNSET&&!feedUrl.isNullOrEmpty())
                searchFeed()
            else if(feedId > ID_UNSET)
                loadFeedFromDb(feedId)
        }

    }

    private fun searchFeed(){
        try {
            // Issue search
            val url: URL = sloppyLinkToStrictURL(textSearch.text.toString().trim())

            listResults.visibility = View.GONE
            emptyText.visibility = View.GONE
            loadingProgress.visibility = View.VISIBLE

            searchJob = searchForFeeds(url)
        } catch (exc: Exception) {
            exc.printStackTrace()
            Toast.makeText(this@EditFeedActivity,
                    R.string.could_not_load_url,
                    Toast.LENGTH_SHORT).show()
        }
    }

    private fun loadFeedFromDb(id:Long)=lifecycleScope.launch(Dispatchers.IO) {
        feed=feedDao.loadFeed(id)
        feed?.let {
            withContext(Dispatchers.Main) {
                textTitle.setText(it.title)
                textTag.setText(it.tag)
                textUrl.setText(it.url.toString())
                switchSync.isChecked=it.syncAble
                feedSyncPeriod.setText(it.sync_period.toString())
                ruleSync.isChecked=it.ruleAble
                backupSwitch.isChecked=it.backup
                overwriteSwitch.isChecked=it.overWrite
                fullPageLoad.isChecked=it.fullTextSync
                preDownload.isChecked=it.preDownload
                reFormatBody.isChecked=it.bodyReFormat
                imagePreDownload.isChecked=it.imagePreDownload
                mutableServer.isChecked = it.mutableServerFeed
                mutableServerButton.isEnabled = it.mutableServerFeed
            }
        }
    }

    override fun onStart() {
        super.onStart()
        settingsViewModel.liveThemePreference.observe(this, androidx.lifecycle.Observer {
            delegate.localNightMode = it
        })
    }

    private fun useEntry(title: String, url: String,syncAble:Boolean=true,syncPeriod:Int=0,ruleAble:Boolean=false) {
        // Cancel search task so it doesn't keep showing results
        searchJob?.cancel()
        @Suppress("DEPRECATION")
        feedTitle = android.text.Html.fromHtml(title).toString()
        feedUrl = url.trim()
        textUrl.setText(feedUrl)
        textTitle.setText(feedTitle)
        detailsFrame.visibility = View.VISIBLE
        searchFrame.visibility = View.GONE
        switchSync.isChecked = syncAble
        feedSyncPeriod.setText(syncPeriod.toString())
        ruleSync.isChecked = ruleAble
        backupSwitch.isChecked = false
        fullPageLoad.isChecked = false
        preDownload.isChecked = false
        imagePreDownload.isChecked = false
        reFormatBody.isChecked = false
        // Focus on tag
        textTag.requestFocus()
        val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.showSoftInput(textTag, 0)
    }

    private inner class FeedResult(view: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(view), View.OnClickListener {

        var textTitle: TextView = view.findViewById(R.id.feed_title)
        var textUrl: TextView = view.findViewById(R.id.feed_url)
        var textDescription: TextView = view.findViewById(R.id.feed_description)
        var item: Feed? = null

        init {
            view.setOnClickListener(this)
        }

        override fun onClick(v: View?) {
          item?.let{
                useEntry(it.title ?: "untitled", it.feed_url ?: feedUrl ?: "")
            }
        }
    }

    private inner class ResultsAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<FeedResult>() {

        private var items: List<Feed> = emptyList()
        var data: List<Feed>
            get() = items
            set(value) {
                items = value
                notifyDataSetChanged()
            }

        override fun onBindViewHolder(holder: FeedResult, position: Int) {
            val item = items[position]

            holder.item = item
            holder.textTitle.text = item.title ?: ""
            holder.textDescription.text = item.description ?: ""
            holder.textUrl.text = item.feed_url ?: ""
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedResult =
                FeedResult(LayoutInflater.from(parent.context)
                        .inflate(R.layout.view_feed_result, parent, false))

        override fun getItemCount(): Int = items.size

    }

    private fun searchForFeeds(url: URL): Job = lifecycleScope.launch(Dispatchers.Default) {
        withContext(Dispatchers.Main) {
            resultAdapter.data = emptyList()
        }
        val results = mutableListOf<Feed>()
        val possibleFeeds = feedParser.getAlternateFeedLinksAtUrl(url).map {
            sloppyLinkToStrictURL(it.first)
        } + url
        possibleFeeds.map {
            launch {
                try {
                    feedParser.parseObjectUrl(it)?.let { feed ->
                        withContext(Dispatchers.Main) {
                            results.add(feed)
                            resultAdapter.data = results
                            // Show results, unless user has clicked on one
                            if (detailsFrame.visibility == View.GONE) {
                                searchFrame.visibility = View.VISIBLE
                                listResults.visibility = View.VISIBLE
                            }
                        }
                    }
                } catch (e: Throwable) {
                    e.printStackTrace()
                }
            }
        }.toList().joinAll()

        withContext(Dispatchers.Main) {
            loadingProgress.visibility = View.GONE
            if (resultAdapter.data.isEmpty()) {
                emptyText.text = getString(R.string.no_such_feed)
                emptyText.visibility = View.VISIBLE
            }
        }
    }
}
